home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
BBS in a Box 3
/
BBS in a box - Trilogy III.iso
/
Files
/
Prog
/
B-C
/
C++Source Code Fmtr Folder
/
Tests
/
UMemory.cp
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS/Acorn
UTF-8
Wrap
Text File
|
1991-01-07
|
41.3 KB
|
1,714 lines
|
[
TEXT/MPS
]
/*$P*/
/*[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]*/
/* UMemory.inc1.p */
/* Copyright © 1985-1990 by Apple Computer, Inc. All rights reserved. */
#ifndef __UMEMEORY__
#include "UMemory.h"
#endif
#ifndef __UFAILURE__
#include "UFailure.h"
#endif
#ifndef __MEMORY__
#include "Memory.h"
#endif
#ifndef __TEXTEDIT__
#include "Textedit.h"
#endif
#ifndef __OSUTILS__
#include "OSUtils.h"
#endif
#ifndef __UMACAPPUTILITIES__
#include "UMacAppUtilities.h"
#endif
#ifndef __SYSEQU__
#include "SysEqu.h"
#endif
#ifndef __TRAPS__
#include "Traps.h"
#endif
#ifndef __DEVICES__
#include "Devices.h"
#endif
#ifndef __ULOMEM__
#include "ULoMem.h"
#endif
#ifndef __TOOLUTILS__
#include "ToolUtils.h"
#endif
#ifndef __RESOURCES__
#include "Resources.h"
#endif
#ifndef __PACKAGES__
#include "Packages.h"
#endif
#ifndef __ERRORS__
#include "Errors.h"
#endif
#ifndef __UDEBUG__
#include "UDebug.h"
#endif
#ifndef __SEGLOAD__
#include "SegLoad.h"
#endif
#if !qDebugTheDebugger
#pragma W+
#pragma R-
#pragma Init-
#pragma OV-
#endif
// Globals to this module and externally available.
extern Size gMaxLockedRsrc;
#if qDebug
extern Boolean gMemMgtBreak = false;
extern Boolean gRsrcReport = false;
extern Boolean gSegReport = false;
#endif
HandleListHandle gSysMemList;
HandleListHandle gApp1MemList;
HandleListHandle gApp2MemList;
HandleListHandle gCodeSegs;
BoolListHandle gIsLoadedSeg;
BoolListHandle gIsResidentSeg;
short gCodeRefNum;
Boolean gUnloadAllSegs;
ProcPtr gGZPurgeNotify;
// Static, globals to this module. Many of these are static by convention, but we don't
// declare them as static because people may want to examine them.
static Boolean pDuringGrowZone;
Size pSzCodeReserve;
Boolean pReserveExists;
Handle pMemReserve;
Handle pCodeReserve;
Boolean pOKCodeReserve;
Boolean pPermAllocation;
short pMaxSegNum;
Size pSzMemReserve;
short pOldResFile;
Boolean pLoadSegCalledFromOwnApp;
TrapPatch pSegLoadPatch;
LongListHandle pSegSize;
// Function prototypes for some routines in this module.
pascal long GrowZoneProc (Size needed);
pascal void BuildCodeReserve (Size allocLim, Boolean fromGZ);
pascal Boolean IsHandleEligible (Handle h);
// Function prototypes for the routines in UMemory.a
pascal void ALoadMacAppSeg (void);
pascal void APostLoadMacAppSeg (void);
/* LoadSeg is Patched to call ALoadMacAppSeg, which in turn calls
LoadMacAppSegment. ALoadMacAppSeg can only be referenced as a
procedure pointer, because no args are declared */
// Other function prototypes that are externally defined.
typedef pascal void (*DoToFrameType) (long, long, long, long, void*);
pascal void EachFrameDo (long calleeFrame, long ppc,
pascal void DoToFrame (long calleeFrame,
long ppc,
long callerFrame,
long itsFrame,
void* scopeLink),
void *scopeLink);
pascal Boolean PreloadSegment (short segNum);
pascal void CallNotify (Handle h, ProcPtr routine) = { 0x205F, 0x4E90 }; // MOVE.L (A7)+,A0; JSR (A0)
/*--------------------------------------------------------------------------------------------------*/
/*
These "MAFoo" functions are primarily for THINK™ Pascal compatibility (but useful in the larger
problem of multiple open resource maps in general); when running under the THINK™ environment,
CODE resources are not found in the same resource file as other application resources, so a
UseResFile call needs to be made to bring the project resource file into the search path.
"gCodeRefNum" is set up at initialization time.
!!! A much more general solution to "the resource problem" appears to be warranted.
*/
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal Handle MAGet1Resource (ResType rType, short rID)
{
short oldResFile;
Handle resource;
oldResFile = MAUseResFile (gCodeRefNum);
resource = Get1Resource (rType, rID);
MAUseResFile (oldResFile);
return resource;
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal Handle MAGet1NamedResource (ResType rType, const Str255& name)
{
short oldResFile;
Handle namedResource;
oldResFile = MAUseResFile (gCodeRefNum);
namedResource = Get1NamedResource (rType, name);
MAUseResFile (oldResFile);
return namedResource;
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal Handle MAGet1IndResource (ResType rType, short index)
{
short oldResFile;
Handle indResource;
oldResFile = MAUseResFile (gCodeRefNum);
indResource = Get1IndResource (rType, index);
MAUseResFile (oldResFile);
return indResource;
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal short MACount1Resources (ResType rType)
{
short oldResFile;
short resourceCnt;
oldResFile = MAUseResFile (gCodeRefNum);
resourceCnt = Count1Resources (rType);
MAUseResFile (oldResFile);
return resourceCnt;
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal Handle MAGetResource (ResType rType, short rID)
{
Handle h;
short oldResFile;
oldResFile = MAUseResFile (gCodeRefNum);
h = GetResource (rType, rID);
MAUseResFile (oldResFile);
return HomeResFile (h) != gCodeRefNum ? NULL : h;
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal Handle MAGetNamedResource (ResType rType, const Str255& name)
{
Handle h;
short oldResFile;
oldResFile = MAUseResFile (gCodeRefNum);
h = GetNamedResource (rType, name);
MAUseResFile (oldResFile);
return HomeResFile (h) != gCodeRefNum ? NULL : h;
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal Handle MAGetIndResource(ResType rType, short index)
{
Handle h;
short oldResFile;
oldResFile = MAUseResFile (gCodeRefNum);
h = GetIndResource (rType, index);
MAUseResFile (oldResFile);
return HomeResFile (h) != gCodeRefNum ? NULL : h;
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal short MACountResources(ResType rType)
{
short oldResFile;
short resourceCnt;
oldResFile = MAUseResFile (gCodeRefNum);
resourceCnt = CountResources (rType);
MAUseResFile (oldResFile);
return resourceCnt;
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal Handle GetSegResource (short segNum)
{
return MAGet1Resource (kCode, segNum);
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMiniInit
pascal void AddAllRsrc (ResType rType, HandleListHandle toList)
{
Boolean oldResLoad;
short i, nResources, theID;
Handle h;
ResType theType;
Str255 theName;
oldResLoad = GetResLoad ();
SetResLoad (false);
nResources = CountResources (rType);
for (i=1; i<=nResources; i++)
{
h = GetIndResource (rType, i);
GetResInfo (h, theID, theType, theName);
/* If there is a ROM resource for this type and ID, don't put it
on the list. */
UseROMMap (false);
h = GetResource (rType, theID);
UseROMMap (false);
if (HomeResFile (h) != 1)
AddHandle (h, toList);
}
SetResLoad (oldResLoad);
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMiniInit
pascal void AddHandle(Handle h, HandleListHandle toList)
{
long offset;
offset = Munger ((Handle) toList, 0, NULL, 0, (Ptr) &h, 4);
FailMemError ();
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMiniInit
pascal long AddSegSizes (Handle segRsrc)
{
SignedByte savedState;
SignedBytePtr p;
Boolean oldResLoad;
long total;
Handle seg;
short i;
Str255 s;
savedState = LockHandleHigh (segRsrc);
oldResLoad = GetResLoad ();
SetResLoad (false);
p = (SignedBytePtr) *segRsrc;
i = *((IntegerPtr) p);
p += 2;
total = 0;
for (; i>0; i--, p+=*p+1)
{
BlockMove ((Ptr) p, (Ptr) &s, *p + 1);
seg = MAGet1NamedResource (kCode, s);
if (seg != NULL)
total += SizeResource (seg) + 8;
}
SetResLoad (oldResLoad);
HSetState (segRsrc, savedState);
return total;
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
#pragma Push
#if qTrace
#pragma D+
#endif
pascal void BuildAllReserves ()
{
static const short initVal = 0xF7;
Boolean oldPerm;
#if qDebug
Size theSize;
#endif
/* set the permanent flag to ensure that the code reserve is
actually allocated and not given up to the low space reserve */
oldPerm = pPermAllocation;
pPermAllocation = true;
BuildCodeReserve (kGZMaxAlloc, false); // make sure code reserve is OK
// reallocate the low space handle, if necessary
if (IsHandlePurged (pMemReserve))
{
ReallocHandle (pMemReserve, pSzMemReserve);
#if qDebug
theSize = GetHandleSize (pMemReserve);
#pragma Push
#pragma R-
if (theSize != 0)
BlockSet (*pMemReserve, theSize, initVal);
#pragma Pop
#endif
}
pPermAllocation = oldPerm; // reset the permanent flag
}
#pragma Pop
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
#pragma Push
#if qTrace
#pragma D+
#endif
pascal void BuildCodeReserve(Size allocLim, Boolean fromGZ)
{
static const short initVal = 0xF7;
Size needed, avail;
Handle canPurge = 0;
#if qDebug
Size theSize;
#endif
pOKCodeReserve = true; // default value
#if qDebug
pReserveShortfall = 0;
if (!pPermAllocation)
ProgramBreak ("BuildCodeReserve called with pPermAllocation = FALSE");
#endif
if (!pReserveExists)
{
pReserveExists = true; // default value
// free the current code reserve
if (IsHandleEligible (pCodeReserve))
EmptyHandle (pCodeReserve);
// compute amt actually needed
needed = Min (pSzCodeReserve - TotalTempSize (FALSE, canPurge) - 8, allocLim);
if (needed > 0)
{
// make as much memory available as possible
if (IsHandleEligible (pMemReserve))
EmptyHandle (pMemReserve);
if (fromGZ) // Never purge or compact from GrowZone
avail = allocLim;
else
{
PurgeMem (needed);
avail = CompactMem (needed);
}
if (avail < needed) // could not get the whole reserve
{
#if qDebug
pReserveShortfall = needed - avail;
#endif
pOKCodeReserve = false;
pReserveExists = false;
needed = avail; // get the most we can
}
if (!fromGZ && (IsHandlePurged (pCodeReserve) || IsHandleEligible (pCodeReserve)))
ReallocHandle (pCodeReserve, needed);
#if qDebug
theSize = GetHandleSize (pCodeReserve);
#pragma Push
#pragma R-
if (theSize != 0)
BlockSet (*pCodeReserve, theSize, initVal);
#pragma Pop
#endif
if (!IsHandlePurged (pCodeReserve))
{
/* Large handles are almost as bad as nonrelocatable blocks.
Try to get this guy out of the way, just in case.*/
if (!fromGZ)
MoveHHi (pCodeReserve);
}
}
}
}
/*$Pop*/
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal Boolean CheckReserve ()
{
BuildAllReserves ();
return pOKCodeReserve;
}
/*--------------------------------------------------------------------------------------------------*/
#if qDebug
#pragma segment MAMemoryRes
pascal void CheckRsrcUsage ()
{
long sz;
Handle h;
Str255 s;
sz = TotalTempSize (true, h);
if (sz > gMaxLockedRsrc)
{
gMaxLockedRsrc = sz;
if (gRsrcReport)
{
NumToString (gMaxLockedRsrc, s);
s = " = New maximum resources usage: " + s + " =";
ProgramReport (s, gMemMgtBreak);
}
}
}
#endif
/*--------------------------------------------------------------------------------------------------*/
#if qDebug
#pragma segment MADebug
pascal void DoChangeReserve (Boolean alter,
Size& codeReserve, Size& codeShort, Size& lowSpaceReserve,
Boolean& gotCode, Boolean& gotLowSpace)
{
long x;
Str255 s;
if (alter)
{
cout << "code reserve size = " << pSzCodeReserve << " ";
if (pOKCodeReserve)
cout << " (OK)\n";
else
cout << " (gone)\n";
cout << "low space reserve size = " << pSzMemReserve << " ";
if (!IsHandlePurged (pMemReserve))
cout << " (OK)\n";
else
cout << " (gone)\n";
cout << "\n";
cout << "New code reserve (-1 == no change): ";
cin >> x;
if (x >= 0)
codeReserve = x;
else
codeReserve = pSzCodeReserve;
cout << "New low space reserve (-1 == no change): ";
cin >> x;
if (x >= 0)
lowSpaceReserve = x;
else
lowSpaceReserve = pSzMemReserve;
cout << "Reset max resource usage (Y or N) [N]? ";
cin >> s;
if (s != "")
{
if ((s[1] == 'y') || (s[1] == 'Y'))
gMaxLockedRsrc = 0;
}
cout << "\n";
SetReserveSize (codeReserve, lowSpaceReserve);
}
else
BuildAllReserves ();
codeReserve = pSzCodeReserve;
codeShort = pReserveShortfall;
lowSpaceReserve = pSzMemReserve;
gotCode = pOKCodeReserve;
gotLowSpace = !IsHandlePurged (pMemReserve);
}
#endif
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMiniInit
/* Called from InitUMemory so that InitUMemory can be in the main segment
and this code can be in another (unloadable) segment. */
pascal void DoInitUMemory (Size& sizeTempReserve, Size sizeLowSpaceReserve)
{
struct Mem { long codeVal, lowSpaceVal, stackVal; };
typedef Mem *MemPtr, **MemHandle;
short i, rsrcCnt;
Boolean oldResLoad;
Handle seg, h;
long StackTot;
short rsrcID;
ResType rsrcType;
Str255 rsrcName;
short lastRsrc;
short mainSegment, utilitySegment;
// Initialize memory management globals
pPermAllocation = false;
pMemReserve = NewHandle (0);
FailNIL (pMemReserve);
pSzMemReserve = 0;
pCodeReserve = NewHandle (0);
FailNIL (pCodeReserve);
pSzCodeReserve = 0;
gGZPurgeNotify = NULL;
pOKCodeReserve = true;
pReserveExists = false;
gUnloadAllSegs = true;
gCodeRefNum = HomeResFile (GetResource (kCode, 1)); /* Get homeresfile of "Main". It better be
there!!*/
pMaxSegNum = 0;
//###########################################
// No resource loading
oldResLoad = GetResLoad ();
SetResLoad (false);
// Figure the highest segment number
lastRsrc = MACount1Resources (kCode);
/* some development systems may not have contiguous numbering of CODE segments.
try to be polite about handling it */
for (i=1; i<= lastRsrc; i++)
{
seg = MAGet1IndResource (kCode, i);
/* we only have an index… find the real resource ID and keep track
of the highest one */
if (seg != NULL)
{
GetResInfo (seg, rsrcID, rsrcType, rsrcName);
pMaxSegNum = (short) Max (rsrcID, pMaxSegNum);
}
}
SetResLoad (oldResLoad); // in case of failure
// Allocate the master segment lists.
gCodeSegs = (HandleListHandle) NewHandle (pMaxSegNum * sizeof (Handle));
FailNIL (gCodeSegs);
gIsResidentSeg = (BoolListHandle) NewHandle (sizeof (Boolean) * pMaxSegNum);
FailNIL (gIsResidentSeg);
gIsLoadedSeg = (BoolListHandle) NewHandle (sizeof (Boolean) * pMaxSegNum);
FailNIL (gIsLoadedSeg);
/* (NOTE: assumes application doesn't change the CODE segment size at runtime
(a very safe assumption)). Used in GetSegFromPC. */
pSegSize = (LongListHandle) NewHandle (sizeof (long) * pMaxSegNum);
FailNIL (pSegSize);
oldResLoad = GetResLoad (); // OK, suppress segment loading again
SetResLoad (false); /* !!! Need an MAResLoad that returns old
state */
// Initialize segment lists.
for (i=1; i<=pMaxSegNum; i++)
(*gIsResidentSeg)[i] = false;
// Segments and their sizes and actual loaded state (helps catch preloads)
for (i=1; i<=pMaxSegNum; i++)
{
seg = GetSegResource (i);
(*gCodeSegs)[i] = seg;
if (seg != NULL) // seg is non-nil if the segment number
{
(*pSegSize)[i] = SizeResource (seg);
(*gIsLoadedSeg)[i] = IsHandleLocked (seg);
}
else
{
(*pSegSize)[i] = 0;
(*gIsLoadedSeg)[i] = false;
}
}
SetResLoad(oldResLoad);
//###########################################
mainSegment = GetSegNumber ((ProcPtr) &InitUMemory); // Main is always resident
(*gIsResidentSeg)[mainSegment] = true;
(*gIsLoadedSeg)[mainSegment] = true;
utilitySegment = GetSegNumber ((ProcPtr) &UnloadAllSegments); // Utilities are always resident
(*gIsResidentSeg)[utilitySegment] = true;
(*gIsLoadedSeg)[utilitySegment] = true;
// init the gSysMemList
gSysMemList = HandleListHandle (NewHandle (0));
FailNIL (gSysMemList);
AddAllRsrc ('LDEF', gSysMemList);
AddAllRsrc ('CDEF', gSysMemList);
AddAllRsrc ('MDEF', gSysMemList);
AddAllRsrc ('WDEF', gSysMemList);
AddAllRsrc ('PACK', gSysMemList);
// Compute memory slop needed
sizeTempReserve = 0;
sizeLowSpaceReserve = 0;
StackTot = 0;
rsrcCnt = CountResources ('seg!');
for (i=1; i<rsrcCnt; i++)
{
h = GetIndResource ('seg!', i);
sizeTempReserve += AddSegSizes (h);
ReleaseResource (h);
}
rsrcCnt = CountResources ('mem!');
for (i=1; i<rsrcCnt; i++)
{
h = GetIndResource ('mem!', i);
{
const Mem& memH = **((MemHandle) h);
sizeTempReserve += memH.codeVal;
sizeLowSpaceReserve += memH.lowSpaceVal;
StackTot += memH.stackVal;
}
ReleaseResource (h);
}
SetStackSpace (StackTot);
MaxApplZone ();
gApp1MemList = NULL;
gApp2MemList = NULL;
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal void FailNoReserve ()
{
if (!CheckReserve ())
Failure (memFullErr, 0);
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal void FailSpaceIsLow ()
{
#if qDebug
MAName s;
if (gAskFailure && CanReadLn ())
{
GetCallersMethodName (s);
if (ReadYesNo ("FailSpaceIsLow called by " + s + ". Return true(Y or N) [N]? "))
Failure (memFullErr, 0);
}
#endif
if (MemSpaceIsLow ())
Failure (memFullErr, 0);
}
/*--------------------------------------------------------------------------------------------------*/
#pragma Push
#if qTrace
#pragma D+
#endif
#pragma segment MAMemoryRes
pascal void GetReserveSize (Size& szCodeReserve, Size& szMemReserve)
{
szCodeReserve = pSzCodeReserve;
szMemReserve = pSzMemReserve;
}
#pragma Pop
/*--------------------------------------------------------------------------------------------------*/
#pragma Push
#if qTrace
#pragma D+
#endif
/* no %_BP/%_EP allowed in here, because we
cannot call to any other segment from this
procedure */
#pragma segment MAMemoryRes // Shouldn't be unloaded
pascal short GetSegFromPC (long ppc)
{
long pc, segStart;
short i;
Handle seg;
pc = *((LongIntPtr) ppc);
/* Since GetSegFromPC may be called before gCodeSegs is set up, we have to test if gCodeSegs == NULL
before using it. */
if (gCodeSegs != NULL)
for (i=1; i<=pMaxSegNum; i++)
{
seg = (*gCodeSegs)[i]; // get segment handle
if ((seg != NULL) && !IsHandlePurged (seg)) // it's in memory
{
segStart = StripLong(*seg); // get segment start
if ((pc >= segStart) && (pc < segStart + (*pSegSize)[i]))
return i;
}
}
return 0; // default return
}
#pragma Pop
/*--------------------------------------------------------------------------------------------------*/
#pragma Push
#if qTrace
#pragma D+
#endif
/* no %_BP/%_EP allowed in here, because we
cannot call to any other segment from this
procedure */
#pragma segment MAMemoryRes /* must be in Main segment because we call
this in order to make the resident segment
resident */
pascal short GetSegNumber (ProcPtr aProc)
/* Gets seg number from a Jump table address */
{
static const short kLoaded = 0x4EF9; // if loaded then a JMP instruction
static const short kUnLoaded = 0x3F3C; // if unloaded then a LoadSeg trap
if (*((IntegerPtr) aProc) == kLoaded) // loaded segment
return *((IntegerPtr) ((Ptr) aProc - 2));
else if ((*IntegerPtr(aProc)) == kUnLoaded) // unloaded segment
return *((IntegerPtr) ((Ptr) aProc + 2));
else /* routine that computed &proc was in same
segment as the proc */
{
#if qDebug
ProgramBreak("GetSegNumber was not passed an jump table address");
#endif
return 0;
}
}
#pragma Pop
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
#pragma Push
#if qTrace
#pragma D+
#endif
pascal Size GetSegSize (short segNum)
{
return (*pSegSize)[segNum];
}
#pragma Pop
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
#pragma Push
#if qTrace
#pragma D+
#endif
pascal long GrowZoneProc (Size)
{
long result, reserveSize, OldA5;
Handle canPurge;
Size codeSize;
OldA5 = SetCurrentA5 (); // Can be called from other worlds
result = 0; // default is to fail
if (!pDuringGrowZone) // prevent re-entrancy
{
pDuringGrowZone = true;
// on a temp alloc, free all code slack immediately
if (!pPermAllocation && IsHandleEligible (pCodeReserve))
{
EmptyHandle (pCodeReserve);
pReserveExists = false;
result = 1;
}
if (result == 0) /* try harder: see if we can purge a code
segment or reduce the code reserve handle
*/
{
// compute size of resources currently in memory
codeSize = TotalTempSize (false, canPurge);
// see if the code reserve handle is too large
if (IsHandleEligible (pCodeReserve))
/* we have a code reserve handle; this implies permanent allocation,
otherwise the handle would have been emptied above */
{
reserveSize = GetHandleSize (pCodeReserve);
/* the following test is an optimization to avoid calling
BuildCodeReserve if there is no hope of reducing
the code reserve handle */
if (codeSize + reserveSize + 8 > pSzCodeReserve)
{ // reserve is too big
pReserveExists = false;
// this should lower the code reserve
BuildCodeReserve (reserveSize, true);
// see if we succeeded in freeing some memory
if (IsHandlePurged (pCodeReserve))
result = 1;
else if (GetHandleSize (pCodeReserve) < reserveSize)
result = 1;
}
}
if ((result == 0) && (canPurge != NULL) && (!pPermAllocation ||
IsHandlePurged (pCodeReserve))) /* got something; only purge it if this is
temporary || we know there is too much
code in memory already */
{
if (gGZPurgeNotify != NULL)
CallNotify (canPurge, gGZPurgeNotify);
reserveSize = GetHandleSize (canPurge);
HPurge (canPurge);
EmptyHandle (canPurge);
pReserveExists = false;
if (pPermAllocation) // don't free too much however
BuildCodeReserve (reserveSize, true);
result = 1;
}
}
if ((result == 0) && IsHandleEligible (pMemReserve)) /* last ditch attempt-free emergency
reserve*/
{
EmptyHandle (pMemReserve);
result = 1;
}
pDuringGrowZone = false;
}
OldA5 = SetA5 (OldA5);
return result;
}
#pragma Pop
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
#pragma Push
#if qTrace
#pragma D+
#endif
pascal Boolean IsHandleEligible (Handle h)
{
if (h == NULL)
return false; // Thanks Pillar!
else if (IsHandlePurged (h))
return false;
else
return (h != GetGZMoveHnd ()) && (h != GetGZRootHnd ());
}
#pragma Pop
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes /* Must be in same segment as grow zone proc */
#pragma Push
#if qTrace
#pragma D+
#endif
pascal void InstallGrowZoneProc ()
/* Once called the grow zone proc's segment CAN!be moved since we're passing a NON-JT address
to SetGrowZone (so we can be called from "other worlds" */
{
THz aZone;
pDuringGrowZone = false;
aZone = ApplicZone ();
aZone->flags |= 0x0400;
/* set the Memory Manager bit that says to always call the
Grow Zone proc, even in "non-critical" situations */
SetGrowZone (&GrowZoneProc);
}
#pragma Pop
/*--------------------------------------------------------------------------------------------------*/
#pragma segment Main /* Must be in main segment and called from main segment */
pascal void InitUMemory ()
{
Size codeRes, lowSpaceRes = 0;
Handle miniInitSeg;
/* Get these segments out of the way so that when DoInitUMemory gets called and the next
block of master pointers gets allocated they won't constipate the heap */
miniInitSeg = GetResource (kCode, GetSegNumber ((ProcPtr) &DoInitUMemory));
if (miniInitSeg != NULL)
{
UnloadSeg (&DoInitUMemory);
LockHandleHigh (miniInitSeg);
}
DoInitUMemory (codeRes, lowSpaceRes);
UnloadAllSegments (); /* get init segment(s) out of middle of heap,
so SetReserveSize has maximum space to
work with */
if (miniInitSeg != NULL) /* Yes, this would eventually get purged if
the space was needed badly enough, but
that happens very late in the game and can
confound the unwary */
EmptyHandle (miniInitSeg);
InstallGrowZoneProc ();
SetReserveSize (codeRes, lowSpaceRes);
if (!pOKCodeReserve) /* couldn't get code reserve. Can't continue */
Failure(memFullErr, 0);
else
{
// Set up the LoadSeg patch
//!!! needs fixing before final!!!
if (!qModelFar)
FailOSErr (PatchTrap (pSegLoadPatch, _LoadSeg, (Ptr) &ALoadMacAppSeg));
}
}
/*--------------------------------------------------------------------------------------------------*/
#pragma Push
#if qTrace
#pragma D+
#endif
/* no %_BP/%_EP allowed in here, because we
cannot call to any other segment from this
procedure */
#pragma segment MAMemoryRes // must be in Main segment
pascal long LoadMacAppSegment (short segNum)
{
#if qDebug
short id;
ResType kind;
Str255 segName;
MAName s;
Handle seg;
#endif
long A5RegisterOnEntry;
long loadMacAppSegment;
A5RegisterOnEntry = SetCurrentA5 (); // ***** Called from trap patches *****
loadMacAppSegment = pSegLoadPatch.oldTrapAddr; // Where to go next
if (GetA5 () != A5RegisterOnEntry)
{
// not called from our application… don't do patch behaviour. Thank you McSink!
pLoadSegCalledFromOwnApp = false;
if (SetA5 (A5RegisterOnEntry) != 0);
}
else
{
pLoadSegCalledFromOwnApp = true;
pOldResFile = MAUseResFile (gCodeRefNum); /* Must set a global because we return from
this function and then forward to the
actual segment loader which should also be
pointing to the _now_ correct resfile.
When we get called back again in
PostLoadMacAppSegment we will restore the
old resFile as the current resFile. Sorry
about the global. */
#if qDebug
if (!GetResLoad ())
{
SetResLoad (true);
ProgramBreak ("Whoops… LoadSeg called with resload set false");
Failure (minErr, 0); /*??? Assign an error code someday or
setresload to true ???*/
}
#endif
if (!PreloadSegmentResource(segNum))
{
#if qDebug
GetCallersMethodName (s);
SetResLoad (false);
seg = MAGet1Resource (kCode, segNum);
GetResInfo (seg, id, kind, segName);
SetResLoad (true);
ProgramBreak ("In " + s + form (" couldn''t load segment: %d", segNum) + segName);
#endif
Failure (memFullErr, 0);
}
(*gIsLoadedSeg)[segNum] = true;
#if qDebug
if (gSegReport)
{
// Cause the debugger to break at the start of the next routine.
gReportNext = true;
GetResInfo ((*gCodeSegs)[segNum], id, kind, segName);
gReportInfo = form (" *** Segment Loaded: %d ", segNum) + segName;
gSingleStep = gMemMgtBreak;
}
#endif
}
return loadMacAppSegment;
}
#pragma Pop
/*--------------------------------------------------------------------------------------------------*/
#pragma Push
#if qTrace
#pragma D+
#endif
/* no %_BP/%_EP allowed in here, because we
cannot call to any other segment from this
procedure */
#pragma Z+
#pragma segment MAMemoryRes // must be in Main segment
pascal void PostLoadMacAppSegment ()
{
long A5RegisterOnEntry;
A5RegisterOnEntry = SetCurrentA5 (); // ***** Called from trap patches *****
if (GetA5 () != A5RegisterOnEntry || !pLoadSegCalledFromOwnApp)
{
// not called from our application… don't do patch behaviour. Thank you McSink!
SetA5 (A5RegisterOnEntry);
}
else
{
// Called back from our glue. Restores current res file pointer.
if (pLoadSegCalledFromOwnApp)
MAUseResFile (pOldResFile);
SetA5 (A5RegisterOnEntry);
}
}
#pragma Pop
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes // Must be in Main segment
pascal void LoadResidentSegments ()
{
short resIndex, i, offset, segNumber, rsrcCnt;
Handle nameList, seg;
SignedBytePtr p;
Str255 name;
ResType theType;
rsrcCnt = CountResources('res!');
for (resIndex=1; resIndex<=rsrcCnt; resIndex++)
{
nameList = GetIndResource ('res!', resIndex);
HNoPurge (nameList);
offset = 2;
for (i=1; i<=*((IntegerPtr) *nameList); i++)
{
p = (SignedBytePtr) *nameList + offset;
BlockMove ((Ptr) p, (Ptr) &name, *p + 1);
offset += name.Length () + 1;
seg = MAGet1NamedResource (kCode, name);
if (seg != NULL)
{
GetResInfo (seg, segNumber, theType, name);
SetResidentSegment (segNumber, true);
}
}
HPurge (nameList);
ReleaseResource (nameList);
}
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal Boolean MemSpaceIsLow ()
{
BuildAllReserves ();
return IsHandlePurged (pMemReserve);
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal Handle NewPermHandle (Size logicalSize)
{
static const short initVal = 0xF3; // odd at all byte boundaries
Boolean priorPerm;
Handle aHandle;
priorPerm = PermAllocation (true);
aHandle = NewHandle (logicalSize);
pPermAllocation = priorPerm;
FailNIL (aHandle);
#pragma Push
#pragma R-
if (qDebug)
BlockSet (*aHandle, logicalSize, initVal);
#pragma Pop
return aHandle;
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal Ptr NewPermPtr (Size logicalSize)
{
static const short initVal = 0xF3; // odd at all byte boundaries
Boolean priorPerm;
Ptr aPtr;
priorPerm = PermAllocation (true);
aPtr = NewPtr (logicalSize);
pPermAllocation = priorPerm;
FailNIL (aPtr);
#pragma Push
#pragma R-
if (qDebug)
BlockSet(aPtr, logicalSize, initVal);
#pragma Pop
return aPtr;
}
/*--------------------------------------------------------------------------------------------------*/
#pragma Push
#if qTrace
#pragma D+
#endif
#pragma segment MAMemoryRes
pascal Boolean PermAllocation (Boolean permanent)
{
Boolean permAllocation = pPermAllocation;
if (permanent != pPermAllocation)
{
pPermAllocation = permanent;
if (permanent)
BuildCodeReserve (kGZMaxAlloc, false);
}
return permAllocation;
}
#pragma Pop
/*--------------------------------------------------------------------------------------------------*/
#pragma Push
#if qTrace
#pragma D+
#endif
/* no %_BP/%_EP allowed in here, because we
cannot call to any other segment from this
procedure */
#pragma segment MAMemoryRes // must be in Main segment
class LWithCodeResFileDo {
short& fSegNum;
Handle& fSeg;
public:
LWithCodeResFileDo (short& segNum, Handle& seg) : fSegNum (segNum), fSeg (seg) { }
pascal void DoGetSegHandle ()
{ fSeg = Get1Resource (kCode, fSegNum); }
};
pascal Boolean PreloadSegmentResource (short segNum)
{
Handle seg;
LWithCodeResFileDo scopeLink (segNum, seg);
if (qDebug && pPermAllocation)
{
cout << "segment # = " << segNum;
ProgramBreak ("Trying to load a segment with PermAllocation == true.");
}
WithCodeResFileDo ((DoWithResFileType) &LWithCodeResFileDo::DoGetSegHandle, &scopeLink);
if (seg == NULL)
return false;
else
{
if (!IsHandleLocked (seg)) // not yet locked
LockHandleHigh (seg);
return true;
}
}
#pragma Pop
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal void RemHandle (Handle h, HandleListHandle toList)
{
long p, maxP, offset;
p = (long) *toList; // Address of first element
maxP = p + GetHandleSize ((Handle) toList); // Address past last element
// Skip elements until item is found
while ((p < maxP) && *((LongIntPtr) p) != (long) h)
p += sizeof (Handle);
if (p < maxP) // Item was found
{
offset = Munger ((Handle) toList, p - (long) *toList,
NULL, sizeof (Handle), (Ptr) &h, 0);
FailMemError ();
}
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
#pragma Push
#if qTrace
#pragma D+
#endif
typedef Handle *HandlePtr;
pascal void ScanList (HandleListHandle list, DoToHandlesType DoToHandle, void *)
{
short i = (short) (GetHandleSize ((Handle) list) / sizeof (Handle));
HandlePtr p = (HandlePtr) *list;
for (; i>0; i--, p++)
DoToHandle (*p, NULL);
}
pascal void ScanHandles (DoToHandlesType DoToHandle, void *)
{
ScanList (gCodeSegs, DoToHandle, NULL);
if (gApp1MemList != NULL)
ScanList (gApp1MemList, DoToHandle, NULL);
ScanList (gSysMemList, DoToHandle, NULL);
if (gApp2MemList != NULL)
ScanList (gApp2MemList, DoToHandle, NULL);
}
#pragma Pop
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal void SetPermHandleSize (Handle h, Size newSize)
{
static const short initVal = 0xF3;
Boolean priorPerm;
#if qDebug
Size oldSize;
#endif
priorPerm = PermAllocation (true);
#if qDebug
oldSize = GetHandleSize (h);
#endif
SetHandleSize (h, newSize);
pPermAllocation = priorPerm; /* Since we are in the memory unit we can
break the encapsulation of the
PermAllocation Call to just set the
pPermAllocation flag back directly. This
lets us be assured that no operations have
occurred that would invalidate the MemErr
flag… thus the following call will give a
true result*/
FailMemError ();
#if qDebug
#pragma Push
#pragma R-
if (oldSize < newSize)
BlockSet ((Ptr) *h + oldSize, newSize - oldSize, initVal);
#pragma Pop
#endif
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal void SetPermPtrSize (Ptr p, Size newSize)
{
static const short initVal = 0xF5;
Boolean priorPerm;
#if qDebug
Size oldSize;
#endif
priorPerm = PermAllocation (true);
#if qDebug
oldSize = GetPtrSize (p);
#endif
SetPtrSize (p, newSize);
pPermAllocation = priorPerm; /* Since we are in the memory unit we can
break the encapsulation of the
PermAllocation Call to just set the
pPermAllocation flag back directly. This
lets us be assured that no operations have
occurred that would invalidate the MemErr
flag… thus the following call will give a
true result*/
FailMemError ();
#if qDebug
#pragma Push
#pragma R-
if (oldSize < newSize)
BlockSet ((Ptr) p + oldSize, newSize - oldSize, initVal);
#pragma Pop
#endif
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
pascal void SetReserveSize (Size forCode, Size forOther)
{
pSzCodeReserve = forCode;
pSzMemReserve = forOther;
// Since the numbers have changed, make sure we start from scratch.
pReserveExists = false;
EmptyHandle (pMemReserve);
BuildAllReserves ();
}
/*--------------------------------------------------------------------------------------------------*/
#pragma Push
#if qTrace
#pragma D+
#endif
/* no %_BP/%_EP allowed in here, because we
cannot call to any other segment from this
procedure */
#pragma segment MAMemoryRes // must be in Main segment
pascal void SetResidentSegment(short segNum, Boolean makeResident)
{
#if qDebug
short id;
ResType kind;
Str255 segName;
MAName s;
Handle seg;
#endif
//!!! needs fixing before final!!!
if (qModelFar)
return;
if (makeResident)
{
(*gIsResidentSeg)[segNum] = true;
if (!PreloadSegment (segNum))
{
#if qDebug
GetCallersMethodName (s);
SetResLoad (false);
seg = MAGet1Resource (kCode, segNum);
SetResLoad (true);
GetResInfo (seg, id, kind, segName);
ProgramBreak ("In " + s + form (" couldn''t load segment: %d", segNum) + segName);
#endif
Failure (memFullErr, 0);
}
}
else
(*gIsResidentSeg)[segNum] = false;
}
#pragma Pop
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMiniInit
pascal void SetStackSpace (long numBytes)
{
long newLimit;
newLimit = (long) GetCurStackBase () - numBytes;
if ((long) GetApplLimit () > newLimit)
SetApplLimit ((Ptr) newLimit);
}
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
#pragma Push
#if qTrace
#pragma D+
#endif
class LTotalTempSize {
Boolean& fJustLocked;
Handle& fCanPurge;
Size& fTotal;
THz& fApplZone;
public:
LTotalTempSize (Boolean& justLocked, Handle& canPurge, Size& total, THz& applZone)
: fJustLocked (justLocked), fCanPurge (canPurge), fTotal (total), fApplZone (applZone) { }
pascal void TotalUp(Handle h)
{
Boolean hIsLocked;
if (!IsHandlePurged (h)) // in memory already
if (HandleZone (h) == fApplZone) // in application heap
{
HNoPurge (h);
hIsLocked = IsHandleLocked (h);
if (!fJustLocked || hIsLocked)
fTotal += GetHandleSize (h) + 8;
// add in the size plus heap overhead
if (!hIsLocked)
if (fCanPurge == NULL)
if (IsHandleEligible (h))
fCanPurge = h;
}
}
};
pascal Size TotalTempSize (Boolean justLocked, Handle& canPurge)
{
Size total;
THz applZone;
LTotalTempSize scopeLink (justLocked, canPurge, total, applZone);
canPurge = NULL;
total = 0;
applZone = ApplicZone ();
ScanHandles ((DoToHandlesType) <otalTempSize::TotalUp, &scopeLink);
return total;
}
#pragma Pop
/*--------------------------------------------------------------------------------------------------*/
#pragma segment MAMemoryRes
#pragma Push
#if qTrace
#pragma D+
#endif
pascal void WithCodeResFileDo (pascal void (*DoWithResFile) (void* scopeLink), void* scopeLink)
{
short oldResFile;
oldResFile = MAUseResFile (gCodeRefNum);
DoWithResFile (scopeLink);
MAUseResFile (oldResFile);
}
#pragma Pop
/*--------------------------------------------------------------------------------------------------*/
#pragma Push
#if qTrace
#pragma D+
#endif
/* no %_BP/%_EP allowed in here, because we
cannot call to any other segment from this
procedure */
#pragma segment MAMemoryRes // must be in Main segment
class LUnloadAllSegments {
Handle& seg;
long& jmpTablePtr;
public:
LUnloadAllSegments (Handle& aSeg, long& aJmpTablePtr)
: seg (aSeg), jmpTablePtr (aJmpTablePtr) { }
pascal void DoToFrame (long, long ppc,
long, long)
{
short seg;
seg = GetSegFromPC (ppc);
if ((seg != 0) && !((*gIsResidentSeg)[seg] && (*gIsLoadedSeg)[seg]))
{
cout << "Segment#: " << seg;
ProgramBreak("I really don''t think that you want to unload a segment into which you are going to return!");
}
}
pascal void UnloadEm ()
{
short i;
for (i=1; i<=pMaxSegNum; i++)
{
if (!(*gIsResidentSeg)[i] && (*gIsLoadedSeg)[i])
{
seg = (*gCodeSegs)[i];
if ((seg != NULL) && !IsHandlePurged (seg))
{
UnloadSeg ((Ptr) jmpTablePtr + **((IntegerHandle) seg) + 2);
(*gIsLoadedSeg)[i] = false;
}
}
}
}
};
pascal void UnloadAllSegments (void)
{
long jumpTablePtr;
Handle seg;
//!!! needs fixing before final!!!
if (qModelFar)
return;
#if qDebug
CheckRsrcUsage ();
#endif
if (gUnloadAllSegs)
{
jumpTablePtr = (long ) GetA5 () + GetCurJTOffset ();
LUnloadAllSegments localScope (seg, jumpTablePtr);
#if qDebug
EachFrameDo ((long) GetCurStackFramePtr (),
(long) GetCurStackFramePtr () + 4,
(DoToFrameType) &LUnloadAllSegments::DoToFrame, &localScope);
#endif
WithCodeResFileDo ((DoWithResFileType) &LUnloadAllSegments::UnloadEm, &localScope);
if (gSegReport)
ProgramReport (" *** Just unloaded all segments ***", gMemMgtBreak);
}
}
#pragma Pop
/*--------------------------------------------------------------------------------------------------*/
#if qDebug
#pragma segment MADebug
pascal void WriteReserves ()
/* WRITELN's the temporary reserve and low-memory reserves in the
debug window. */
{
WrLblPtr ("Temporary reserve (pCodeReserve)", (long) pCodeReserve);
cout << "\n";
WrLblPtr ("Low-memory reserve (pMemReserve)", (long) pMemReserve);
cout << "\n";
}
#endif